#include "src/pbc/portable-handler-table.h"

#include <iomanip>

namespace portable {

HandlerTable::HandlerTable(int size)
    : raw_entries_data_(size) {
}

int HandlerTable::GetRangeStart(int index) const {
  P_DCHECK_LT(index, NumberOfRangeEntries());
  return raw_entries_data_[index].range_start;
}

int HandlerTable::GetRangeEnd(int index) const {
  P_DCHECK_LT(index, NumberOfRangeEntries());
  return raw_entries_data_[index].range_end;
}

int HandlerTable::GetRangeHandlerBitfield(int index) const {
  P_DCHECK_LT(index, NumberOfRangeEntries());
  return raw_entries_data_[index].range_handler;
}

int HandlerTable::GetRangeHandler(int index) const {
  return HandlerOffsetField::decode(GetRangeHandlerBitfield(index));
}

int HandlerTable::GetRangeData(int index) const {
  P_DCHECK_LT(index, NumberOfRangeEntries());
  return raw_entries_data_[index].range_data;
}

HandlerTable::CatchPrediction HandlerTable::GetRangePrediction(
    int index) const {
  return HandlerPredictionField::decode(GetRangeHandlerBitfield(index));
}

bool HandlerTable::HandlerWasUsed(int index) const {
  return HandlerWasUsedField::decode(GetRangeHandlerBitfield(index));
}

void HandlerTable::SetRangeStart(int index, int value) {
  raw_entries_data_[index].range_start = value;
}

void HandlerTable::SetRangeEnd(int index, int value) {
  raw_entries_data_[index].range_end = value;
}

void HandlerTable::SetRangeHandler(int index, int handler_offset,
                                   CatchPrediction prediction) {
  int value = HandlerOffsetField::encode(handler_offset) |
              HandlerWasUsedField::encode(false) |
              HandlerPredictionField::encode(prediction);
  raw_entries_data_[index].range_handler = value;
}

void HandlerTable::SetRangeData(int index, int value) {
  raw_entries_data_[index].range_data = value;
}

int HandlerTable::NumberOfRangeEntries() const {
  return static_cast<int>(raw_entries_data_.size());
}

void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
  os << "   from   to       hdlr (prediction,   data)\n";
  for (int i = 0; i < NumberOfRangeEntries(); ++i) {
    int pc_start = GetRangeStart(i);
    int pc_end = GetRangeEnd(i);
    int handler_offset = GetRangeHandler(i);
    int handler_data = GetRangeData(i);
    CatchPrediction prediction = GetRangePrediction(i);
    os << "  (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
       << ")  ->  " << std::setw(4) << handler_offset
       << " (prediction=" << prediction << ", data=" << handler_data << ")\n";
  }
}

int HandlerTable::length() {
  return static_cast<int>(raw_entries_data_.size());
}

}  // namespace portable
